/*
*  Copyright (c) 2006-2020, Chukie
*
*  SPDX-License-Identifier: Apache-2.0
*
*  @file     : cellular_netdev.c
*
*  @brief    :
*  Website   : https://gitee.com/open-embedded
*
*
*  Change Logs:
*  Date           Author          Notes
*  2020-06-23     zhaocj       The first version
*/
/* Includes -----------------------------------------------------------------*/
#include "cellular_netdev.h"
#ifdef RT_USING_NETDEV
#include "lwip/ip.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"

#define DBG_TAG "[CELL-NETDEV]"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#ifndef RT_USING_ULOG
    #define log_hex(tag,width,buf,size)
#endif /*RT_USING_ULOG*/
/* Private typedef ----------------------------------------------------------*/
/* Private define -----------------------------------------------------------*/
/* Private variables --------------------------------------------------------*/
/* Extern variables ---------------------------------------------------------*/
extern const struct netdev_ops lwip_netdev_ops;
extern const ip_addr_t *dns_getserver(u8_t numdns);
extern void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver);
/* Private function prototypes ----------------------------------------------*/


/* Public function prototypes -----------------------------------------------*/

/**
 * @brief add netdev into netdev
 *
 * @param netdev    he piont of netdev obj
 * @param netif the piont of netif control block
 * @return rt_err_t
 */
rt_err_t cellular_netdev_add(struct netdev *netdev, struct netif *netif)
{
#define LWIP_NETIF_NAME_LEN 2
    int result = 0;
    char name[LWIP_NETIF_NAME_LEN + 1] = {0};

    RT_ASSERT(netif);
    RT_ASSERT(netdev);


#ifdef SAL_USING_LWIP
    extern int sal_lwip_netdev_set_pf_info(struct netdev * netdev);

    /* set the lwIP network interface device protocol family information */
    sal_lwip_netdev_set_pf_info(netdev);
#endif /* SAL_USING_LWIP */

    rt_strncpy(name, netif->name, LWIP_NETIF_NAME_LEN);
    result = netdev_register(netdev, name, (void *)netif);
    if (RT_EOK != result)
    {
        return result;
    }

    /* Update netdev info after registered */
    netdev->flags = netif->flags;
    netdev->mtu = netif->mtu;
    netdev->ops = &lwip_netdev_ops;
    //netdev->hwaddr_len =  NETDEV_HWADDR_MAX_LEN;
    netdev->ip_addr = netif->ip_addr;
    netdev->gw = netif->gw;
    netdev->netmask = netif->netmask;

    LOG_D("netdev->flags: 0x%X", netdev->flags);
    LOG_D("netdev->mtu: %d", netdev->mtu);
    LOG_D("netdev->ops: 0x%p", netdev->ops);
    LOG_D("netdev->hwaddr_len: %d", netdev->hwaddr_len);
    LOG_D("netdev->hwaddr: ");
    log_hex("hwaddr", 0, netdev->hwaddr, netdev->hwaddr_len);
    LOG_D("netdev->ip_addr: %s", inet_ntoa(netdev->ip_addr));
    LOG_D("netdev->gw: %s", inet_ntoa(netdev->gw));
    LOG_D("netdev->netmask: %s", inet_ntoa(netdev->netmask));
    LOG_D("netdev->dns1: %s", inet_ntoa(netdev->dns_servers[0]));
    LOG_D("netdev->dms2: %s", inet_ntoa(netdev->dns_servers[1]));
    LOG_D("pppif->linkoutput: 0x%p", netif->linkoutput);
    LOG_D("pppif->input: 0x%p", netif->input);
    return result;
}

/**
 * @brief Synchronize infomation between netdev and ppp netif
 *
 * @param netdev
 * @param netif
 * @return rt_err_t
 */
rt_err_t cellular_netdev_sync(struct netdev *netdev, struct netif *netif)
{
    RT_ASSERT(netif);
    RT_ASSERT(netdev);

    rt_strncpy(netdev->name, netif->name, LWIP_NETIF_NAME_LEN);
    netdev->flags = netif->flags;
    netdev->mtu = netif->mtu;
    netdev->ip_addr = netif->ip_addr;
    netdev->gw = netif->gw;
    netdev->netmask = netif->netmask;

    /* sometime we can get second dns server but first dns server is empty, wo need do something to fix it */
#if LWIP_DNS
    if (!ip_addr_isany(dns_getserver(0)))
    {
        netdev_low_level_set_dns_server(netdev, 0, dns_getserver(0));
    }
    if (!ip_addr_isany(dns_getserver(1)))
    {
        netdev_low_level_set_dns_server(netdev, 1, dns_getserver(1));
    }
#endif /*LWIP_DNS*/

    return RT_EOK;
}

#if LWIP_DNS
/**
 * @brief add user dns to dns server list
 *
 * @param netdev
 * @param netif
 * @param dns
 * @return rt_err_t
 */
rt_err_t cellular_netdev_add_dns(struct netdev *netdev, struct netif *netif, const ip_addr_t *dns)
{
    RT_ASSERT(netif);
    RT_ASSERT(netdev);
    RT_ASSERT(dns);
#if DNS_MAX_SERVERS > 0
    /* sometime we can get second dns server but first dns server is empty, wo need do something to fix it */
    if (ip_addr_isany(dns_getserver(0)))
    {
        netdev_low_level_set_dns_server(netdev, 0, dns);
        dns_setserver(0, dns);
    }
#if DNS_MAX_SERVERS > 1
    else if (ip_addr_isany(dns_getserver(1)))
    {
        netdev_low_level_set_dns_server(netdev, 1, dns);
        dns_setserver(1, dns);
    }
#endif /*DNS_MAX_SERVERS > 1*/
#if DNS_MAX_SERVERS > 2
    else if (ip_addr_isany(dns_getserver(2)))
    {
        netdev_low_level_set_dns_server(netdev, 2, dns);
        dns_setserver(2, &dns);
    }
#endif /*DNS_MAX_SERVERS > 2*/
#if DNS_MAX_SERVERS > 3
    else if (ip_addr_isany(dns_getserver(3)))
    {
        netdev_low_level_set_dns_server(netdev, 3, dns);
        dns_setserver(3, &dns);
    }
#endif /*DNS_MAX_SERVERS > 3*/
    else
    {
        LOG_E("DNS server list full!");
        return RT_ERROR;
    }
#else
#error "DNS is not enable!";
#endif /*DNS_MAX_SERVERS > 0*/

    return RT_EOK;
}
#endif /*LWIP_DNS*/

/**
 * @brief delete ppp netdev from netdev list
 *
 * @param netdev
 */
void cellular_netdev_del(struct netdev *netdev)
{
    if (netdev)
    {
        netdev_unregister(netdev);
    }
}

/**
 * @brief set netdev hardware address
 *
 * @param netdev
 * @param addr
 * @param addr_len
 * @return rt_err_t
 */
rt_err_t cellular_netdev_set_hwaddr(struct netdev *netdev, uint8_t *addr, int addr_len)
{
    RT_ASSERT(netdev);
    RT_ASSERT(addr);
    if (addr_len > NETDEV_HWADDR_MAX_LEN || addr_len == 0)
    {
        return -RT_EINVAL;
    }
    netdev->hwaddr_len = MIN(addr_len, NETDEV_HWADDR_MAX_LEN);
    memcpy(netdev->hwaddr, addr, netdev->hwaddr_len);
    log_hex("hwaddr", 0, netdev->hwaddr, netdev->hwaddr_len);
    return RT_EOK;
}


#endif /*RT_USING_NETDEV*/
/* End of file****************************************************************/

